#pragma once

#include <iostream>
#include <cstring>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/errno.h>
#include <functional>

#include "Common.hpp"
#include "Log.hpp"
#include "InetAddr.hpp"
#include "SingleThreadPool.hpp"

using namespace LogMoudle;
using namespace SingleThreadPoolMouble;

static const int gport=8080;

static const int BACKLOG=10; // 一般不要太大也不要太小了

using handle_t =std::function<std::string(std::string)>;   // 服务器任务类型

class TcpServer
{
    struct ThreadData
    {
       int sockfd;
       TcpServer* self;
    };

    using task_t = std::function<void()>;  // 创建线程池执行任务类型，规定标注类型

public:
    TcpServer(handle_t handle,int port=gport)
    :_port(port),_running(false),_handle(handle)
    {}
    void Init()
    {
        //1. 创建Linsten socket
        _listensock=socket(AF_INET,SOCK_STREAM,0);
        if(_listensock<0)
        {
            LOG(LogLevel::FATAL)<<"Socket error "<<strerror(errno);
            Die(SOCKET_ERR);
        }
        LOG(LogLevel::NORMAL)<<"Socket success..";
        //2. bind
        sockaddr_in local;
        memset(&local,0,sizeof(local));
        local.sin_family=AF_INET;
        local.sin_port=htons(_port);
        local.sin_addr.s_addr=INADDR_ANY;   // 我们之前说过服务器不建议设置为固定的公网IP，最好设置为0.0.0.0
        socklen_t slen=sizeof(local);
        int n=bind(_listensock,CONV(&local),slen);
        if(n<0)
        {
            LOG(LogLevel::FATAL)<<"bind error "<<strerror(errno);
            Die(BIND_ERR);
        }
        LOG(LogLevel::NORMAL)<<"bind success..";
        // 3. listen
        if(listen(_listensock,BACKLOG)<0)
        {
            LOG(LogLevel::FATAL)<<"listen error " <<strerror(errno);
            Die(LISTEN_ERR);
        }  
        LOG(LogLevel::NORMAL)<<"Listen success..";

       // signal(SIGCHLD,SIG_IGN);  //linux 特有
       ThreadPool<task_t>::GetInstance()->Start();
       signal(SIGPIPE,SIG_IGN);
       int opt=1;
       setsockopt(_listensock,SOL_SOCKET,SO_REUSEADDR |SO_REUSEPORT,&opt,sizeof(opt));  // 防止偶然性的服务器终止无法立刻重启
    }
    void Run()
    {
        _running=true;
        while(_running)
        {
            struct sockaddr_in cli;
            memset(&cli,0,sizeof(cli));
            socklen_t len=sizeof(cli);
            int socketfd=accept(_listensock,CONV(&cli),&len);
            if(socketfd<0)
            {
                // 这里如果分配失败，再进行分配就行，所以这里报错给个warnning就可以了
                LOG(LogLevel::WARNNING)<<"accept error "<<strerror(errno);
                continue;
            }
            LOG(LogLevel::NORMAL)<<"accept success...";
            InetAddr addr(cli);
            LOG(LogLevel::NORMAL)<<"client information : "<<addr.Addr()<<" socketfd: "<<socketfd;
            //  version -0
            //  Handle(socketfd);

            // // version-1 多线程版
            //  pid_t t=fork();
            // if(t==0)
            // {
            //     // 父子进程各有一张fd文件描述符表
            //     close(_listensock);  // 关掉不使用的文件描述符，防止误操作
            //     Handle(socketfd);
            //     exit(0);   // 子进程只执行服务，不让他往下继续循环了
            // }
            // close(socketfd);  // 关掉不使用的文件描述符，防止误操作
            // pid_t rid=waitpid(t,nullptr,0);
            // if(rid<0)
            // {
            //     LOG(LogLevel::WARNNING)<<"waitpid error";
            // }
            // // version-2 多线程版
            // pid_t t=fork();
            // if(t==0)
            // {
            //     // 父子进程各有一张fd文件描述符表
            //     close(_listensock);  // 关掉不使用的文件描述符，防止误操作
            //     pid_t pid=fork();
            //     if(pid>0) exit(0);
            //     // 孙子进程
            //     Handle(socketfd);
            //     exit(0);   // 子进程只执行服务，不让他往下继续循环了
            // }
            // close(socketfd);  // 关掉不使用的文件描述符，防止误操作
            // pid_t rid=waitpid(t,nullptr,0);
            // if(rid<0)
            // {
            //     LOG(LogLevel::WARNNING)<<"waitpid error";
            // }
            
            // version3 多线程版
            // pthread_t tid;
            // ThreadData* data=new ThreadData;
            // data->self=this;
            // data->sockfd=socketfd;
            // pthread_create(&tid,nullptr,Entrance,data);
            
            // version4 线程池版   适合于短任务或用户量少的场景
           
            // task_t task=std::bind(&TcpServer::Handle,this,socketfd);  bind 构造任务
           // ThreadPool<task_t>::GetInstance()->Equeue(task);

            ThreadPool<task_t>::GetInstance()->Equeue([this,socketfd](){  
                this->Handle(socketfd);
            });  //lambda 构建任务

        }
    }
    static void*  Entrance(void* data)
    {
        ThreadData* t=static_cast<ThreadData*>(data);  // static_cast 这个类是用于安全转换类型
        t->self->Handle(t->sockfd);
        return nullptr;
    }
    void Handle(int socketfd)
    {
        char buffer[4096];
        while(true)
        {
            int n=read(socketfd,buffer,sizeof(buffer)-1);
            if(n>0)
            {
                 buffer[n]=0;
                // std::cout<<"client say#: " <<buffer;
                // std::string message="Tcpserver echo# ";
                // // 回显
                //message+=buffer;
                std::string message=_handle(buffer);
                message+='\n';
                int m=write(socketfd,message.c_str(),message.size());
                if(m<0)
                {
                    LOG(LogLevel::WARNNING)<<"write error "<<strerror(errno);
                }
            }
            else if(n==0)
            {
                LOG(LogLevel::NORMAL)<<"client socket: "<<socketfd<<" quit ..."; 
                break;
            }
            else 
            {
                LOG(LogLevel::WARNNING)<<"read error"<<strerror(errno);
                break;
            }
        }
        ::close(socketfd);
    }
    ~TcpServer(){}
private:
    handle_t _handle;
    int _listensock;
    int _port;
    bool _running;
};

